【新機能】Python Serverless Microframework for AWS(プレビュー版)が登場!
こんにちは、せーのです。今日は昨今でのクラウド構築での主流となりつつある「サーバレスアーキテクチャ」を更に効率的に構築できる便利ツールをご紹介します。ちょっとワクワクしますよ。
できるだけ速く、できるだけ直感的に
AWSにてサーバレスアーキテクチャを実現するのに一番シンプルな方法は「Lambda + API Gateway」です。要件をREST APIの形に落とし込み、API Gatewayにデプロイ、URLを叩かれたらLambdaが連動して処理を開始する、というものです。Lambdaが自動的にスケールしてくれるので沢山のアクセスがきた時もうまいこと捌いてくれ、EC2無しでシステムの構築が可能となる、というものです。
しかし実際に組んだことがある方はわかるかと思いますが簡単なテストAPIを組むにしてもそこそこの準備が、特にAPI Gateway周りで必要となります。これをもっと直感的にパパっと組みたい。そんな願いを満たしてくれるのが今回プレビュー版としてリリースされた「Python Serverless Microframework for AWS」です。
このフレームワークの設計はPythonerにとってみればDjangoの一人勝ちを阻むかと今年注目されているマイクロフレームワークである「Flask」がベースになっています。軽量で取り回しの効きやすいフレームワークですね。
やってみる
とにかくどれだけ簡単か、見ていただきましょう。
インストール
インストールはPyPlかGithubからとなります。PyPlからサクッと入れてみます。
テストということでvirtualenvを使っておきます。virtualenvについてはこちらの記事を御覧ください。持っていない人は入れておきましょう。
sudo pip install virtualenv virtualenv ~/.virtualenvs/chalice-demo source ~/.virtualenvs/chalice-demo/bin/activate pip install chalice
chalice...聖杯?どういう意味なんでしょう。
chalice --help Usage: chalice [OPTIONS] COMMAND [ARGS]... Options: --help Show this message and exit. Commands: deploy gen-policy local logs new-project
使うコマンドは現在5つです。簡単ですね。
新規プロジェクトを作る
次に新規プロジェクトを作ります。名前は最初らしく「helloworld」にしてみましょう。これもワンライナーです。
Tsuyoshis-iMac:chaliceTest Tsuyoshi$ chalice new-project helloworld Tsuyoshis-iMac:chaliceTest Tsuyoshi$ ls helloworld Tsuyoshis-iMac:chaliceTest Tsuyoshi$ cd helloworld/ Tsuyoshis-iMac:helloworld Tsuyoshi$ ls -l total 8 -rw-r--r-- 1 Tsuyoshi staff 783 7 12 06:57 app.py -rw-r--r-- 1 Tsuyoshi staff 0 7 12 06:57 requirements.txt
プロジェクトを作ると[app.py]と[requirements.txt]という2つのファイル、隠しフォルダとして[.chalice]フォルダが作成されました。app.pyはプログラム本体、requirements.txtはFlaskで使うファイルでライブラリのバージョンを書き込むことで固定させるものです。ではapp.pyの中身を見てみましょう。
from chalice import Chalice app = Chalice(app_name='helloworld') @app.route('/') def index(): return {'hello': 'world'} # The view function above will return {"hello": "world"} # whenver you make an HTTP GET request to '/'. # # Here are a few more examples: # # @app.route('/hello/{name}') # def hello_name(name): # # '/hello/james' -> {"hello": "james"} # {'hello': name} # # @app.route('/users/', methods=['POST']) # def create_user(): # # This is the JSON body the user sent in their POST request. # user_as_json = app.json_body # # Suppse we had some 'db' object that we used to # # read/write from our database. # # user_id = db.create_user(user_as_json) # return {'user_id': user_id} # # See the README documentation for more examples. #
Pythonを知らない方でもコードを読むと何となくわかると思います。ルートパス('/')に対してindexという関数がマッピングされていて{'hello': 'world'}という値を返すんでしょうね。
デプロイ
ではまずそのままデプロイしてみます。。。とその前にAWSアカウントを確認しておいて下さい。~/.aws/configの[default]にAPI KEY, API SECRET KEY, REGIONが書いてあればOKです。
cat ~/.aws/config [default] region = ap-northeast-1 aws_access_key_id = XXXXXXXXXXXXXXXXXX aws_secret_access_key = XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
では、改めてデプロイです。
chalice deploy Initial creation of lambda function. Updating IAM policy. Creating deployment package. Lambda deploy done. Initiating first time deployment... Deploying to: dev https://XXXXXXXXXXXXX.execute-api.ap-northeast-1.amazonaws.com/dev/
なんと、これだけでLambda Functionの作成、API Gatewayの設定、IAM Policyまで自動的に行なってくれます。テストしてみましょう。
curl https://XXXXXXXXXXX.execute-api.ap-northeast-1.amazonaws.com/dev/ {"hello": "world"}
できてます。。。すごい。環境を見てみます。
IAM Role
CloudWatchへの権限が付いているようです。
Lambdaもありました。
API Gatewayもキチンとできてます。
何も書いてないので流石に認証はそのままでした。
これはすごいですね。30秒で環境ができました。
パラメータ付きのAPIを作ってみる
次に動的なパラメータのあるREST APIを作ってみたいと思います。app.pyにメソッドを一つ追加します。
from chalice import Chalice app = Chalice(app_name='helloworld') @app.route('/') def index(): return {'hello': 'world'} @app.route('/{name}/hello') def hello(name): return {'hello': name}
ではデプロイしてみます。
chalice deploy Updating IAM policy. Updating lambda function... Regen deployment package... Sending changes to lambda. Lambda deploy done. API Gateway rest API already found. Deleting root resource id Done deleting existing resources. Deploying to: dev https://XXXXXXXXX.execute-api.ap-northeast-1.amazonaws.com/dev/
できました。テストします。
curl https://XXXXXXXXXXXXXX.execute-api.ap-northeast-1.amazonaws.com/dev/seino/hello {"hello": "seino"}
あっという間ですね。
ログを出してみる
次にログを出してみたいと思います。先ほどのメソッドにワンライナー追加します。
@app.route('/{name}/hello') def hello(name): print('return hello to {}'.format(name)) return {'hello': name}
デプロイしてテストします。
chalice deploy curl https://XXXXXXXXXXXXXX.execute-api.ap-northeast-1.amazonaws.com/dev/seino/hello {"hello": "seino"}
結果は変わりません。ではログを見てみます。
chalice logs ........ 2016-07-12 07:39:16.239000 999bfb START RequestId: 4c5b38b7-47b8-11e6-b927-857ad7ef1c1a Version: $LATEST 2016-07-12 07:39:16.246000 999bfb return hello to seino 2016-07-12 07:39:16.246000 999bfb END RequestId: 4c5b38b7-47b8-11e6-b927-857ad7ef1c1a 2016-07-12 07:39:16.246000 999bfb REPORT RequestId: 4c5b38b7-47b8-11e6-b927-857ad7ef1c1a Duration: 0.41 ms Billed Duration: 100 ms Memory Size: 128 MB Max Memory Used: 15 MB
ログが吐かれている事を確認しました。このログを見る限りLambdaのログですね。ということはCloudWatch Logsのものでしょうか。見てみます。
ありました。ここを見てるんですね。
まとめ
いかがでしたでしょうか。ものすごく簡単です。現在ではこの他にもエラーメッセージの記述、複数メソッドの同時記述(PUTとPOST、とか)、ステージの選択、等もう少し細かい制御が可能となります。これが進化すると開発は非常に楽になりますね!